#include "stdio.h"
#include "string.h"
#include "stdlib.h"
#include "user_sdspi.h"
#include <dirent.h>     // dir struct
#include "esp_log.h"
#include "esp_err.h"
#include "driver/sdspi_host.h"
#include "esp_vfs_fat.h"
#include "esp_vfs.h" 

static const char *TAG = "SDSPI";


// When testing SD and SPI modes, keep in mind that once the card has been
// initialized in SPI mode, it can not be reinitialized in SD mode without
// toggling power to the card.
sdmmc_host_t host = SDSPI_HOST_DEFAULT();
sdmmc_card_t* card;


char dir_temp[DIR_NAM_LEN_MAX];



void mount_sdcard(void)
{
    esp_err_t ret;
    // Options for mounting the filesystem.
    // If format_if_mount_failed is set to true, SD card will be partitioned and
    // formatted in case when mounting fails.
    esp_vfs_fat_sdmmc_mount_config_t mount_config = {
        .format_if_mount_failed = true,
        .max_files = 5,
        .allocation_unit_size = 8 * 1024
    };
    ESP_LOGI(TAG, "Initializing SD card");

    spi_bus_config_t bus_cfg = {
        .mosi_io_num = SPI_MOSI_GPIO,
        .miso_io_num = SPI_MISO_GPIO,
        .sclk_io_num = SPI_SCLK_GPIO,
        .quadwp_io_num = -1,
        .quadhd_io_num = -1,
        .max_transfer_sz = 4000,
    };
    host.max_freq_khz = 1000;
    ret = spi_bus_initialize(host.slot, &bus_cfg, SPI_DMA_CHAN);
    if (ret != ESP_OK) {
        ESP_LOGE(TAG, "Failed to initialize bus.");
        return;
    }

    // This initializes the slot without card detect (CD) and write protect (WP) signals.
    // Modify slot_config.gpio_cd and slot_config.gpio_wp if your board has these signals.
    sdspi_device_config_t slot_config = SDSPI_DEVICE_CONFIG_DEFAULT();
    slot_config.gpio_cs = SPI_CS_GPIO;
    slot_config.host_id = host.slot;

    ret = esp_vfs_fat_sdspi_mount(SD_MOUNT_POINT, &host, &slot_config, &mount_config, &card);

    if (ret != ESP_OK) {
        if (ret == ESP_FAIL) {
            ESP_LOGE(TAG, "Failed to mount filesystem.");
        } else {
            ESP_LOGE(TAG, "Failed to initialize the card (%s). "
                "Make sure SD card lines have pull-up resistors in place.", esp_err_to_name(ret));
        }
        return;
    }

    // Card has been initialized, print its properties
    sdmmc_card_print_info(stdout, card);
}


struct wavinfo get_wav_msg(char * wav_name)
{
    for(int i=0;i<current_list_num;i++)
    {
        if(strstr(list[i].name,wav_name))
        {
            printf("has searched wav\n");
            printf("name: %s\n",list[i].name);
            return list[i];
        }
    }
    printf("not find wav %s\n",wav_name);
    return list[0];
}

char* char_change_A2a(char *raw_char)
{
    char *temp = raw_char ;
    int len = strlen(raw_char);
    // printf("str = %s, len = %d\n",raw_char,len);
    for(int a = 0; a<len; a++)
    {
        // printf("str: %c\t",temp[a]);
        if('A'<=temp[a]&&temp[a]<='Z')
            temp[a]=temp[a]+32;
    }
    // printf("temp = %s\n",temp);
    // printf("raw_char = %s\n",raw_char);
    return temp;
}

void dir_list(char *path)
{
    char *dir_name;
    if(path != NULL)
        dir_name = path;
    else
        dir_name = SD_MOUNT_POINT;//"/t1";
        
    ESP_LOGI(TAG, "Opening dir %s", dir_name);

    DIR *dir_t1 = opendir(dir_name);

    int count = 0;
    char* names[DIR_NUM_MAX];

    printf("DIR: %s\n",dir_name);
    while(1) {
        struct dirent* de = readdir(dir_t1);
        if (!de) {
            break;
        }
        
        names[count] = char_change_A2a(de->d_name);

        printf("\t%s\n", de->d_name);
        // printf("\t%s type = %d\n", de->d_name, de->d_type);

        // dir
        if(de->d_type == 2)
        {
            strcpy(dir_temp,dir_name);
            strcat(dir_temp,"/");
            strcat(dir_temp,de->d_name);
            printf("this is dir:%s\n",dir_temp);

            char * temp_cpr;
            temp_cpr = "system~1";
            // printf("%s,%s",de->d_name , temp_cpr);
            if(strcmp(de->d_name,temp_cpr)==0)
                printf("ignore this dir\n");
            else
            {
                // strcpy(dir_temp,"");
                dir_list(dir_temp);
            }
        }


        // search wav file 
        char* search_key = ".wav";
        // printf("search wav = %s\n",strstr(de->d_name,search_key));
        if(strstr(de->d_name,search_key) != NULL)
        {
            // printf("this is wav file: %s\n",de->d_name);
            int file_name_len = strlen(dir_name)+strlen(de->d_name);
            // printf("file name len = %d\n",file_name_len);
            char *temp_path = (char *)malloc(sizeof(char) * (file_name_len+2));
            strcpy(temp_path,dir_name);
            strcat(temp_path,"/");
            strcat(temp_path,de->d_name);
            printf("file path = %s\n",temp_path);
            struct wavinfo *p1 ;
            p1 = &list[current_list_num];
            current_list_num++;
            p1->name = temp_path;
            printf("p1->name = %s\n",p1->name);
        }
        ++count;
    }
    closedir(dir_t1);
}

void print_wav_list(void)
{
    printf("--------- wav list --------%d\n",current_list_num);

    for(int i=0;i<current_list_num;i++)
    {
        printf("\twav%d: %s\n",i,list[i].name);
    }
}


void test_sd_list(void)
{
    char *temp_path = SD_MOUNT_POINT;
    dir_list(temp_path);
    print_wav_list();
}

